package com.example.port.utils;

import com.example.port.service.impl.CustomUserDetailsService;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.JwtException;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.web.filter.OncePerRequestFilter;

import java.io.IOException;

/**
 * JWT认证过滤器
 */
@RequiredArgsConstructor
public class JwtAuthenticationFilter extends OncePerRequestFilter {
    
    private static final Logger logger = LoggerFactory.getLogger(JwtAuthenticationFilter.class);
    
    private final JwtUtils jwtUtils;
    private final CustomUserDetailsService userDetailsService;
    
    @Override
    protected void doFilterInternal(
            HttpServletRequest request, 
            HttpServletResponse response, 
            FilterChain filterChain) throws ServletException, IOException {
        
        final String requestURI = request.getRequestURI();
        logger.debug("处理请求: " + requestURI);
        
        // 对于不需要认证的路径，直接放行
        if (requestURI.startsWith("/api/auth/") || 
            requestURI.startsWith("/api/swagger-ui/") || 
            requestURI.startsWith("/api/v3/api-docs/")) {
            logger.debug("白名单路径，跳过认证: " + requestURI);
            filterChain.doFilter(request, response);
            return;
        }
        
        // 从请求头中获取JWT Token
        final String authHeader = request.getHeader(Constants.JWT.HEADER_STRING);
        
        // 如果没有Token或者不是Bearer Token，则直接放行
        if (authHeader == null || !authHeader.startsWith(Constants.JWT.TOKEN_PREFIX)) {
            logger.warn("请求无令牌或格式不正确: " + requestURI);
            filterChain.doFilter(request, response);
            return;
        }
        
        // 提取Token
        final String jwt = authHeader.substring(Constants.JWT.TOKEN_PREFIX.length());
        String username = null;
        
        try {
            // 从Token中提取用户名
            username = jwtUtils.extractUsername(jwt);
            logger.debug("从令牌中提取用户名: " + username);
        } catch (ExpiredJwtException e) {
            // 如果是Token过期异常，记录日志但不抛出异常
            logger.info("JWT令牌已过期: " + e.getMessage());
            // 可以设置响应头提示客户端刷新令牌
            response.setHeader("X-JWT-Expired", "true");
        } catch (JwtException e) {
            // 其他JWT异常
            logger.error("JWT令牌错误: " + e.getMessage());
        }
        
        // 如果用户名不为空且当前还没有身份验证
        if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
            try {
                // 从数据库加载用户
                logger.debug("加载用户详情: " + username);
                UserDetails userDetails = this.userDetailsService.loadUserByUsername(username);
                
                // 验证Token是否有效
                boolean isValid = jwtUtils.validateToken(jwt, userDetails);
                logger.debug("令牌验证结果: " + (isValid ? "有效" : "无效") + ", 用户: " + username);
                
                if (isValid) {
                    // 创建认证令牌
                    UsernamePasswordAuthenticationToken authToken = new UsernamePasswordAuthenticationToken(
                            userDetails,
                            null,
                            userDetails.getAuthorities()
                    );
                    
                    // 设置详细信息
                    authToken.setDetails(
                            new WebAuthenticationDetailsSource().buildDetails(request)
                    );
                    
                    // 将认证信息存入上下文
                    SecurityContextHolder.getContext().setAuthentication(authToken);
                    logger.debug("设置认证成功: " + username);
                }
            } catch (Exception e) {
                logger.error("无法设置用户认证: " + e.getMessage(), e);
            }
        }
        
        // 继续过滤链
        filterChain.doFilter(request, response);
    }
}
